package com.zengdada.report.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.zengdada.authority.config.listener.ApplicationReadyEventListener;
import com.zengdada.authority.model.ReportInfo;
import com.zengdada.authority.service.ReportInfoAuthorityService;
import com.zengdada.report.model.ReportExtend;
import com.zengdada.report.service.JasperReportType;
import com.zengdada.report.service.ReportAuthorityService;
import net.sf.jasperreports.engine.*;
import net.sf.jasperreports.engine.export.JRRtfExporter;
import net.sf.jasperreports.export.ExporterOutput;
import net.sf.jasperreports.export.SimpleExporterInput;
import net.sf.jasperreports.export.SimpleOutputStreamExporterOutput;
import net.sf.jasperreports.export.SimpleWriterExporterOutput;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.sql.DataSource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.sql.Connection;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Auther: 12614
 * @Contact: 1261438511@qq.com
 * @Date: 2019/3/12 15:26
 * @Description:
 */
@Service
public class ReportAuthorityServiceImpl implements ReportAuthorityService {

    @Autowired
    DataSource dataSource;
    @Autowired
    @Qualifier("reportInfoAuthorityServiceImpl")
    ReportInfoAuthorityService reportInfoAuthorityService;

    private final static Map<String, ReportExtend> reportCache = new ConcurrentHashMap<String, ReportExtend>();


    @Override
    public String saveTempData(HttpServletRequest request) {
        String key = String.format("%s-%s", new Random().nextInt(1000), new Date().getTime());
        try {
            Enumeration<String> names = request.getParameterNames();
            Map<String, String> map = new HashMap<>();
            while (names.hasMoreElements()) {
                String name = names.nextElement();
                map.put(name, request.getParameter(name));
            }
            ApplicationReadyEventListener.addTempContent(key, map, 300, null);
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
        return key;
    }


    private ReportExtend loadReport(String reportId, HttpServletRequest request) throws IOException, JRException {
        ReportInfo report = reportInfoAuthorityService.selectById(reportId);
        if (report == null) return null;
        report = JSONObject.parseObject(JSONObject.toJSONString(report), ReportExtend.class);
        ((ReportExtend) report).setVersion((report.getModifyTime() != null ? report.getModifyTime() : new Date()).getTime());
        ReportExtend cached = reportCache.get(reportId);
        if (cached == null || !cached.getVersion().equals(((ReportExtend) report).getVersion())) {
            cached = (ReportExtend) report;
            cached.compile(request.getServletContext().getRealPath(cached.getLocation()));
            reportCache.put(reportId, cached);
        }
        return cached;
    }


    @Transactional
    public byte[] report(String reportId, HttpServletRequest request, JasperReportType type) {
        try (Connection connection = dataSource.getConnection()) {
            ReportExtend report = loadReport(reportId, request);
            if (report == null)
                throw new RuntimeException(String.format("报表“%s”不存在", reportId));
            HashMap<String, String> defaultParams = new HashMap<String, String>() {{
                String realPath = request.getServletContext().getRealPath(report.getLocation());
                if (realPath == null) realPath = report.getLocation();
                if (realPath != null && realPath.length() > 0)
                    put("MAIN_REPORT_DIR", realPath.substring(0, realPath.lastIndexOf("\\")));
            }};
            String tempDataId = request.getParameter("tempDataId");
            if (tempDataId != null)
                defaultParams.putAll((Map<String, String>) ApplicationReadyEventListener.getContainerContent(tempDataId));
            HashMap<String, Object> paramValues = new HashMap<>();
            for (JRParameter pm : report.getReport().getParameters()) {
                // 忽略系统内置参数
                if (pm.isSystemDefined()) continue;
                // 取http参数 (先获取默认的参数)
                String rawVal = defaultParams.get(pm.getName());
                if (rawVal == null) rawVal = request.getParameter(pm.getName());
                // 取默认值，暂不支持表达式
                if (StringUtils.isEmpty(rawVal) && pm.getDefaultValueExpression() != null)
                    rawVal = pm.getDefaultValueExpression().toString();
                paramValues.put(pm.getName(), ConvertUtils.convert(rawVal, pm.getValueClass()));
            }
            JasperPrint fillReport = JasperFillManager.fillReport(report.getReport(), paramValues, connection);
            JRAbstractExporter exporter = type.getJrExporterClass().newInstance();
            exporter.setConfiguration(type.getConfigurationClass().newInstance());
            exporter.setExporterInput(new SimpleExporterInput(fillReport));
            try (ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream()) {

//                SimpleOutputStreamExporterOutput  doc
//                SimpleWriterExporterOutput rtf
//                SimpleOutputStreamExporterOutput  html
//                SimpleOutputStreamExporterOutput xls pdf
                ExporterOutput output;
                if (exporter instanceof JRRtfExporter)
                    output = new SimpleWriterExporterOutput(byteOutputStream);
                else
                    output = new SimpleOutputStreamExporterOutput(byteOutputStream);
                exporter.setExporterOutput(output);
                exporter.exportReport();
                return byteOutputStream.toByteArray();
            }
//            return JasperRunManager.runReportToPdf(report.getReport(), paramValues, connection);
        } catch (Exception e) {
//            e.printStackTrace();
            throw new RuntimeException(String.format("生成报表“%s”出错：%s", reportId, e.getMessage()));
        }
    }
}
